package com.fintech.third.utils;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.sun.xml.bind.marshaller.CharacterEscapeHandler;

import cn.hutool.core.util.StrUtil; 

/**
 * 
 * @author xuan.fan
 * 
 * @create May 11, 2016 3:04:32 PM
 * 
 */

public class XMLUtil {

	/**
	 * 
	 * Convert from Object to XML
	 * 
	 * Default encoding UTF-8
	 *
	 * 
	 * 
	 * @param obj
	 * 
	 * @return
	 * 
	 */

	public static String convertToXml(Object obj) {

		return convertToXml(obj, "UTF-8");

	}

	/**
	 * 
	 * Convert from Object to XML
	 *
	 * 
	 * 
	 * @param obj
	 * 
	 * @param encoding
	 * 
	 * @return
	 * 
	 */

	public static String convertToXml(Object obj, String encoding) {

		String result = null;

		StringWriter writer = new StringWriter();

		try {

			JAXBContext context = JAXBContext.newInstance(obj.getClass());

			Marshaller marshaller = context.createMarshaller();

			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

			marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);

			// marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.FALSE);

			marshaller.setProperty("com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler",

					new CharacterEscapeHandler() {

						public void escape(char[] chars, int start,

								int length, boolean isAttVal,

								Writer writer) throws IOException {

							writer.write(chars, start, length);

						}

					});

			marshaller.marshal(obj, writer);

			// result = writer.toString();

			// remove the standalone="yes" in the xml header

			result = writer.toString().replace("standalone=\"yes\"", "");

		} catch (Exception e) {

			throw new RuntimeException(e);

		} finally {

			if (writer != null) {

				try {

					writer.close();

				} catch (IOException e) {

					// TODO Auto-generated catch block

					e.printStackTrace();

				}

			}

		}

		return result;

	}

	/**
	 * 
	 * Convert from XML to Object
	 *
	 * 
	 * JAXB解析xml
	 * 
	 * @param xml
	 * 
	 * @param clazz
	 * 
	 * @return
	 * 
	 */

	@SuppressWarnings("unchecked")

	public static <T> T convertToObject(String xml, Class clazz) {

		T _clazz = null;

		StringReader reader = null;

		try {

			JAXBContext context = JAXBContext.newInstance(clazz);

			Unmarshaller unmarshaller = context.createUnmarshaller();

			reader = new StringReader(xml);

			_clazz = (T) unmarshaller.unmarshal(reader);

		} catch (Exception e) {

			throw new RuntimeException(e);

		} finally {

			if (reader != null) {

				reader.close();

			}

		}

		return _clazz;

	}

	public String createXml(Map<String, String> map,String queryType) {
		Document document=null;  
		try {
	        Element root = DocumentHelper.createElement("conditions");
	        
	        document = DocumentHelper.createDocument(root);  
	        Element conditionElement = root.addElement("condition"); 
	        //给根节点添加属性  
	        conditionElement.addAttribute("queryType", queryType);  
	          
	        //给根节点添加孩子节点  
	        for(String key:map.keySet()){
	        	//element.addElement("name").addAttribute("婚姻", "单身").addText("小章"); 
	        	Element itemElement=conditionElement.addElement("item");
	        	itemElement.addElement("name").addText(key);  
	        	itemElement.addElement("value").addText(map.get(key));  
	        }
	                  
		} catch (Exception e) {
			e.printStackTrace();
		}
		return document.asXML(); 
	}
	/**
	 * 将map转换成xml字符串，墨菲使用
	 * @param map
	 * @return
	 */
	public static String createMoFeiXml(Map<String, String> map) {
		Document document=null;  
		try {
	        Element root = DocumentHelper.createElement("request");
	        document = DocumentHelper.createDocument(root);  
	        //给根节点添加孩子节点  
	        for(String key:map.keySet()){
	        	root.addElement(key).addText(map.get(key));  
	        }
	                  
		} catch (Exception e) {
			e.printStackTrace();
		}
		return document.asXML(); 
	}
	
	public static void main(String[] args) throws Exception{
/*		Map<String,String> map=new HashMap<String,String>();
		map.put("funcode", "1");
		map.put("datetime", "2");
		map.put("merid", "2");
		map.put("transid", "2");
		map.put("mobileid", "2");
		map.put("name", "2");
		map.put("identityNo", "2");
		map.put("license", "2");
		map.put("sign", "2");
		String xmlStr=XMLUtil.createMoFeiXml(map);
		System.out.println(xmlStr);*/
		String xmlStr = "<response><retcode>0501</retcode><funcode>Gmf0000003</funcode><sign>bd694a2b65ee44c417ec08200755dd25</sign><datetime>20180911142744</datetime><transid>1536647243450_0KArV6</transid><model><retcode>0501</retcode><funcode>Gmf0000003</funcode><sign>bd694a2b65ee44c417ec08200755dd25</sign><datetime>20180911142744</datetime><transid>1536647243450_0KArV6</transid></model></response>";
		Map<String, Object> dom2Map = Dom2Map(xmlStr);
		Map<String, Object> model = (Map<String, Object>) dom2Map.get("model");
		System.out.println(model);

	}
	
	 /**
     * 将Document对象转为Map（String→Document→Map）
     * @param Document
     * @return
	 * @throws DocumentException 
     */
    @SuppressWarnings("rawtypes")
    public static Map<String, Object> Dom2Map(String xmlStr) throws DocumentException{ 
    	Map<String, Object> map = new HashMap<String, Object>();  
    	if(StrUtil.isBlank(xmlStr)){
    		return map;
    	}
    	
    	Document doc = DocumentHelper.parseText(xmlStr); 
        if(doc == null)  
            return map;  
        Element root = doc.getRootElement();  
        for (Iterator iterator = root.elementIterator(); iterator.hasNext();) {  
            Element e = (Element) iterator.next();  
            //System.out.println(e.getName());  
            List list = e.elements();  
            if(list.size() > 0){  
                map.put(e.getName(), Dom2Map(e));  
            }else  
                map.put(e.getName(), e.getText());  
        }  
        return map;  
    }

    /**
     * 将Element对象转为Map（String→Document→Element→Map）
     * @param Element
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static Map Dom2Map(Element e){  
        Map map = new HashMap();  
        List list = e.elements();  
        if(list.size() > 0){  
            for (int i = 0;i < list.size(); i++) {  
                Element iter = (Element) list.get(i);  
                List mapList = new ArrayList();  
                if(iter.elements().size() > 0){  
                    Map m = Dom2Map(iter);  
                    if(map.get(iter.getName()) != null){  
                        Object obj = map.get(iter.getName());  
                        if(!obj.getClass().getName().equals("java.util.ArrayList")){  
                            mapList = new ArrayList();  
                            mapList.add(obj);  
                            mapList.add(m); 
                        }  
                        if(obj.getClass().getName().equals("java.util.ArrayList")){  
                            mapList = (List) obj;  
                            mapList.add(m);
                        }  
                        map.put(iter.getName(), mapList); 
                    }else  
                        map.put(iter.getName(), m);  
                }  
                else{  
                    if(map.get(iter.getName()) != null){  
                        Object obj = map.get(iter.getName()); 
                        if(!obj.getClass().getName().equals("java.util.ArrayList")){  
                            mapList = new ArrayList();  
                            mapList.add(obj);  
                            mapList.add(iter.getText());  
                        }  
                        if(obj.getClass().getName().equals("java.util.ArrayList")){  
                            mapList = (List) obj;  
                            mapList.add(iter.getText());  
                        }  
                        map.put(iter.getName(), mapList); 
                    }else  
                        map.put(iter.getName(), iter.getText());//公共map resultCode=0
                }  
            }  
        }else  
            map.put(e.getName(), e.getText());  
        return map;  
    }  

}